"use strict"

import {Native} from './native.js'
import {Task} from './task.js'

/**
 * http常用操作
 * @static
 * @author GuoHua Liu
 * @copyright Copyright © 2019 GuoHua Liu. All rights reserved.
 */
class http {

    /**
     * 支持浏览器:是<br>
     * 把url的参数部分转化成json对象
     * @param {string} url
     * @returns {Object} 返回包含参数的json对象中
     */
    static parseURLQueryString (url) {
        var reg_url = /^[^\?]+\?([\w\W]+)$/,
        reg_para = /([^&=]+)=([\w\W]*?)(&|$|#)/g,
        arr_url = reg_url.exec(url),
        ret = {}
        if (arr_url && arr_url[1]) {
            var str_para = arr_url[1], result
            while ((result = reg_para.exec(str_para)) != null) {
                ret[result[1]] = result[2]
            }
        }
        return ret
    }

    /**
     * 支持浏览器:是<br>
     * 构建带查询参数的url
     * @param {string|Object} url 需要附加参数的url
     * @param {Object|undefined} parameters 查询参数比如{"name":"小主", "age":"18"}
     * @returns {string} 返回处理后的url
     */
    static URL(url, parameters) {
        let newUrl = url
        let params = parameters
        if (!params) {
            params = url
        }

        if (params) {
            var qString = ""
            let first = true
            for ( let key in params)
            {
                // 编码解码函数:
                // escape/unescape/encodeURI/decodeURI/encodeURIComponent/decodeURIComponent
                qString += first ? "" : "&"
                first = false
                qString +=  key + "=" + encodeURIComponent(params[key])
            }
            if (!parameters) {
                return qString
            }
            newUrl += "?" + qString
        }
        return newUrl
    }


    /**
     * 默认提交JSON数据,返回也默认解析为JSON,提交其他格式需要设置Content-Type。
     * 支持通过option.headers控制的Content-Type类型:
     * application/x-www-form-urlencoded;
     * application/json;
     * text/plain
     * @param {String} url
     * @param {Object} httpBody 默认将被编译为JSON字符串提交到服务端
     * @param {Object} option {"headers":{额外的请求头},timeout:超时时间(浮点数单位秒)}
     * @returns {Task} 返回可打断的任务
     */
    static post(url, httpBody, option) {

        let newTask  = new Task()
        newTask.name = "http.post"

        // 默认值
        let contentType = "application/json"
        let timeout = 5.0
        let headers = {}

        if (option && option.headers) {
            headers = option.headers
        }

        if (headers["Content-Type"]) {
            contentType = headers["Content-Type"]
        } else {
            headers["Content-Type"] = "application/json"
        }

        if (option && option.timeout) {
            timeout = option.timeout
        }

        // 标准的判断是否在浏览器环境, 编译的时候自动删除
        if (!Native.getInstance().isHos()) {
            let task = new XMLHttpRequest()

            task.ontimeout = ()=> {
                newTask.__reject({"errMsg":"网络请求超时"})
            }

            task.onreadystatechange = ()=>{
                if (task.readyState === 4) {
                    if (task.status === 200) {
                        let text = task.responseText
                        try {
                            newTask.__resolve(JSON.parse(text))
                        } catch (error) {
                            newTask.__resolve(text)
                        }
                    } else {
                        newTask.__reject({"errMsg": task.status + "错误"})
                    }
                }
            }

            task.open('POST', url, true)

            if (headers) {
                for (let key in headers) {
                    // 该操作需要在open后
                    task.setRequestHeader(key, "" + headers[key])
                }
            }

            if (contentType.indexOf("application/json") == 0) {
                task.send(JSON.stringify(httpBody))
            }  else if (contentType.indexOf("application/x-www-form-urlencoded") == 0) {
                let requestText = http.URL(httpBody)
                console.log("[http]提交url编码数据" + requestText)
                task.send(requestText)
            }

            newTask.__setAbort(()=>{
                task.abort()
            })

            return newTask
        }

        let requestText = null

        if (contentType.indexOf("application/json") == 0) {
            requestText = JSON.stringify(httpBody)
        } else if (contentType.indexOf("application/x-www-form-urlencoded") == 0) {
            requestText = http.URL(httpBody)
        } else if (contentType.indexOf("text/plain") == 0) {
            requestText = httpBody // 直接上传文本
        }

        let task = Native.getInstance().callNative("http", {
            "url":url,
            "method":"post",
            "requestText":requestText,
            "headers" : headers,
            "timeout":timeout
        }, true, data=>{
            let text= data.msg
            try {
                newTask.__resolve(JSON.parse(text))
            } catch (error) {
                newTask.__resolve(text)
            }
        }, error=>{newTask.__reject(error)})

        newTask.__setAbort(()=>{task.abort()})

        return newTask
    }

    /**
      * 支持浏览器:是，可能要配置跨域选项<br>
      * 用于发送简单的GET请求，只支持请求JSON等文本场合。更多的HTTP操作请使用类Http。
      * @param {string} url
      * @param {Object|undefined} parameters 查询参数比如{"name":"小主", "age":"18"}；
      *                            参数会被编码到url后，但是如果你自己已经添加了?，就不要再使用该参数了
      * @param {Object|undefined} option 格式:{"text":true，返回文本，false/默认返回JSON对象, "headers":额外的请求头}
      * @returns {Task} 失败:{"errMsg":错误描述} 成功:JSON对象或者文本
      */
     static get(url, parameters = undefined, option = undefined) {

        if (parameters) {
            url = http.URL(url, parameters)
        }

        let newTask  = new Task()
        newTask.name = "http.get"

        let headers = {}

        if (option && option.headers) {
            headers = option.headers
        }

        if (!Native.getInstance().isHos()) {
            let task = new XMLHttpRequest()
            task.ontimeout = ()=> {
                newTask.__reject({"errMsg":"网络请求超时"})
            }
            task.onreadystatechange = ()=>{
                if (task.readyState === 4) {
                    if (task.status === 200) {
                        let text= task.responseText
                        try {
                            newTask.__resolve(JSON.parse(text))
                        } catch (error) {
                            newTask.__reject(text)
                        }
                    } else {
                        newTask.__reject({"errMsg": task.status + "错误"})
                    }
                }
            }
            task.open('GET', url, true)
            if (headers) {
                for (let key in headers) {
                    task.setRequestHeader(key, "" + headers[key])
                }
            }
            task.send(null)
            newTask.__setAbort(()=>{task.abort()})
            return newTask
        }

        let task = Native.getInstance().callNative("http", {
            "url":url,
            "method":"get",
            "headers" : headers
        }, true, data=>{
            let text= data.msg
            try {
                newTask.__resolve(JSON.parse(text))
            } catch (error) {
                newTask.__resolve(text)
            }
        }, error=>{newTask.__reject(error)})
        newTask.__setAbort(()=>{task.abort()})
        return newTask
    }

    /**
     * 注意该方法为同步方法，大文件建议使用异步方法
     * @param {String} path
     * @returns {XMLHttpRequest} XMLHttpRequest对象
     */
    static xhr(path) {
        let xhr = new XMLHttpRequest();
        xhr.open('get', path, false);
        xhr.send(null)
        return xhr;
    }


    /**
      * 支持浏览器:是，可能要配置跨域选项<br>
      * 使用XMLHttpRequest发送get请求，错误或者成功都可以获得XMLHttpRequest对象
      * @param {string} url
      * @param {Object} parameters 查询参数比如{"name":"小主", "age":"18"}；
      *                            参数会被编码到url后，但是如果你自己已经添加了?，就不要再使用该参数了
      * @param {Object} option 格式:{"headers":额外的请求头}
      * @returns {Task} 失败回调参考:XMLHttpRequest对象 成功回调参考:XMLHttpRequest对象
      */
     static getByXhr(url, parameters, option) {
        if (parameters) {
            url = http.URL(url, parameters)
        }
        let newTask  = new Task()
        newTask.name = "http.getByXhr"
        let headers = {}
        if (option && option.headers) {
            headers = option.headers
        }
        let task = new XMLHttpRequest()
        task.responseType = "blob"
        task.ontimeout = ()=> {
            newTask.__reject(task)
        }
        task.onreadystatechange = ()=>{
            if (task.readyState === 4) {
                // webview特殊的情况，没有填写状态码（状态码为0），因此此种情况也当成功
                if (task.status === 200 || ((task.status === 0) && task.response)) {
                    newTask.__resolve(task)
                } else {
                    newTask.__reject(task)
                }
            }
        }
        task.open('GET', url, true)
        if (headers) {
            for (let key in headers) {
                task.setRequestHeader(key, "" + headers[key])
            }
        }
        task.send(null)
        newTask.__setAbort(()=>{task.abort()})
        return newTask
    }

}
export {http}
